//*********************************************************
//
//    Copyright (c) Microsoft. All rights reserved.
//    This code is licensed under the Apache License, Version 2.0.
//    THIS CODE IS PROVIDED *AS IS* WITHOUT WARRANTY OF
//    ANY KIND, EITHER EXPRESS OR IMPLIED, INCLUDING ANY
//    IMPLIED WARRANTIES OF FITNESS FOR A PARTICULAR
//    PURPOSE, MERCHANTABILITY, OR NON-INFRINGEMENT.
//
//********************************************************* 

using System;
using System.Diagnostics;
using System.Windows.Forms;
using Microsoft.Office.Core;
using Microsoft.TridentWordAddIn.Common;
using CustomTaskPane = Microsoft.Office.Tools.CustomTaskPane;

namespace Microsoft.TridentWordAddIn.AddIn
{
    /// <summary>
    /// Manages the task panes in the add in
    /// </summary>
    public class TaskPaneManager : ITaskPaneManager, IDisposable
    {
        private readonly IWindowContainer windowContainer;
        private bool disposed;

        /// <summary>
        /// Initializes a new instance of the <see cref="TaskPaneManager"/> class.
        /// </summary>
        /// <param name="windowContainer">The window container.</param>
        public TaskPaneManager(IWindowContainer windowContainer)
        {
            this.windowContainer = windowContainer;
        }

        #region ITaskPaneManager Members

        /// <summary>
        /// Delegate for Removing Task Panes
        /// </summary>
        private delegate void RemoveTaskPanesDelegate();

        /// <summary>
        /// Fires when the visibility of a custom task pane changes
        /// </summary>
        public event EventHandler<VisibilityChangedEventArgs> TaskPaneVisibilityChanged;

        /// <summary>
        /// Fires when the dock position of a custom task pane changes
        /// </summary>
        public event EventHandler<DockPositionChangedEventArgs> TaskPaneDockPositionChanged;

        /// <summary>
        /// Sets the task pane visibility.
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="isVisible">if set to <c>true</c> [is visible].</param>
        /// <param name="documentKey">The document key.</param>
        public void SetTaskPaneVisibility(string title, bool isVisible, int documentKey)
        {
            CustomTaskPane pane = this.windowContainer.GetTaskPane(title, documentKey);
            if (pane != null)
            {
                pane.Visible = isVisible;
            }
            else
            {
                Trace.WriteLine("taskePaneWrapper is null, " + title, TraceLevel.Warning.ToString());
            }
        }

        /// <summary>
        /// Creates a custom task pane.
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="userControl">The user control.</param>
        public void CreateTaskPane(string title, UserControl userControl)
        {
            if (userControl == null)
            {
                throw new ArgumentNullException("userControl");
            }

            this.InitializeTaskPane(userControl, title);
        }

        /// <summary>
        /// Removes the task pane.
        /// </summary>
        public void RemoveTaskPanes()
        {
            this.windowContainer.RemoveTaskPanes();
        }

        /// <summary>
        /// Removes the task pane.
        /// </summary>
        /// <param name="title">The title.</param>
        public void RemoveTaskPane(string title)
        {
            this.windowContainer.RemoveTaskPane(title);
        }

        /// <summary>
        /// Determines whether [is task pane visible] [the specified title].
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="documentKey">The document key.</param>
        /// <returns>bool</returns>
        public bool IsTaskPaneVisible(string title, int documentKey)
        {
            bool result = false;
            CustomTaskPane customTaskPane = this.windowContainer.GetTaskPane(title, documentKey);
            if (customTaskPane != null)
            {
                result = customTaskPane.Visible;
            }

            return result;
        }

        /// <summary>
        /// Gets the task pane user control.
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="documentKey">The document key.</param>
        /// <returns>UserControl</returns>
        public UserControl GetTaskPaneUserControl(string title, int documentKey)
        {
            CustomTaskPane customTaskPane = this.GetTaskPane(title, documentKey);
            if (customTaskPane != null)
            {
                return customTaskPane.Control;
            }

            return null;
        }

        #endregion

        #region IDisposable Members

        /// <summary>
        /// Performs application-defined tasks associated with freeing, releasing, or resetting unmanaged resources.
        /// </summary>
        public void Dispose()
        {
            this.Dispose(true);
            GC.SuppressFinalize(this);
        }

        /// <summary>
        /// Returns true if a task pane with the given title exists
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="documentKey">The document key.</param>
        /// <returns>bool</returns>
        public bool TaskPaneExists(string title, int documentKey)
        {
            bool result = false;
            CustomTaskPane taskPane = this.windowContainer.GetTaskPane(title, documentKey);
            if (taskPane != null)
            {
                result = true;
            }

            return result;
        }

        /// <summary>
        /// Disposes the specified the privately held resources.
        /// </summary>
        /// <param name="disposing">if set to <c>true</c> disposes resources.</param>
        private void Dispose(bool disposing)
        {
            // Check to see if Dispose has already been called.
            if (!this.disposed)
            {
                // If disposing equals true, dispose all managed 
                // and unmanaged resources.
                if (disposing)
                {
                }
            }

            this.disposed = true;
        }

        #endregion

        /// <summary>
        /// Gets the task pane.
        /// </summary>
        /// <param name="title">The title.</param>
        /// <param name="documentKey">The document key.</param>
        /// <returns>CustomTaskPane</returns>
        private CustomTaskPane GetTaskPane(string title, int documentKey)
        {
            return this.windowContainer.GetTaskPane(title, documentKey);
        }

        /// <summary>
        /// Initializes the task pane.
        /// </summary>
        /// <param name="userControl">The user control.</param>
        /// <param name="taskPaneTitle">The task pane title.</param>
        /// <returns>CustomTaskPane</returns>
        private CustomTaskPane InitializeTaskPane(UserControl userControl, string taskPaneTitle)
        {
            taskPaneTitle = taskPaneTitle ?? "NO TITLE";

            CustomTaskPane taskPane = this.windowContainer.AddTaskPane(userControl, taskPaneTitle);
            taskPane.Width = Properties.Settings.Default.DefaultTaskPaneWidth;
            taskPane.DockPosition = MsoCTPDockPosition.msoCTPDockPositionRight;

            taskPane.Visible = false;
            taskPane.VisibleChanged += new EventHandler(this.TaskPane_VisibleChanged);
            taskPane.DockPositionChanged += new EventHandler(this.TaskPane_DockPositionChanged);

            return taskPane;
        }

        /// <summary>
        /// Handles the DockPositionChanged event of the taskPane control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TaskPane_DockPositionChanged(object sender, EventArgs e)
        {
            CustomTaskPane taskPane = sender as CustomTaskPane;
            this.OnTaskPaneDockPositionChanged(taskPane);
        }

        /// <summary>
        /// Called when [task pane dock position changed].
        /// </summary>
        /// <param name="taskPane">The task pane.</param>
        private void OnTaskPaneDockPositionChanged(CustomTaskPane taskPane)
        {
            if (this.TaskPaneDockPositionChanged != null)
            {
                TaskPaneDockPositions dockPosition = TaskPaneDockPositions.Floating;
                
                switch (taskPane.DockPosition)
                {
                    case MsoCTPDockPosition.msoCTPDockPositionBottom:
                        dockPosition = TaskPaneDockPositions.Bottom;
                        break;
                    case MsoCTPDockPosition.msoCTPDockPositionTop:
                        dockPosition = TaskPaneDockPositions.Top;
                        break;
                    case MsoCTPDockPosition.msoCTPDockPositionRight:
                        dockPosition = TaskPaneDockPositions.Right;
                        break;
                    case MsoCTPDockPosition.msoCTPDockPositionLeft:
                        dockPosition = TaskPaneDockPositions.Left;
                        break;
                    case MsoCTPDockPosition.msoCTPDockPositionFloating:
                        dockPosition = TaskPaneDockPositions.Floating;
                        break;
                }

                this.TaskPaneDockPositionChanged(taskPane, new DockPositionChangedEventArgs(dockPosition, taskPane.Title));
            }
        }

        /// <summary>
        /// Handles the VisibleChanged event of the taskPane control.
        /// </summary>
        /// <param name="sender">The source of the event.</param>
        /// <param name="e">The <see cref="System.EventArgs"/> instance containing the event data.</param>
        private void TaskPane_VisibleChanged(object sender, EventArgs e)
        {
            CustomTaskPane taskPane = sender as CustomTaskPane;
            this.OnTaskPaneVisibilityChanged(taskPane);
        }

        /// <summary>
        /// Called when [task pane visibility changed].
        /// </summary>
        /// <param name="taskPane">The task pane.</param>
        private void OnTaskPaneVisibilityChanged(CustomTaskPane taskPane)
        {
            if (this.TaskPaneVisibilityChanged != null)
            {
                this.TaskPaneVisibilityChanged(taskPane, new VisibilityChangedEventArgs(taskPane.Visible, taskPane.Title));
            }
        }
    }
}
